from flask import Flask, render_template, jsonify, request
import pandas as pd
import os
import time
import numpy as np
from datetime import datetime
import json
from functools import lru_cache
import threading
import subprocess
import csv
import sys

# 导入我们的数据API模块
from get_data import load_data, get_date_range, preload_data, clear_cache, get_cache_info
from get_data.data_loader import DataLoader
from get_data.cache_manager import CacheManager
from get_data.data_processor import DataProcessor

# 全局变量存储预测进度
prediction_progress = {
    'active': False,
    'progress': 0,
    'stage': '',
    'message': '',
    'timestamp': None
}

app = Flask(__name__)

# 创建全局数据API实例（用于获取详细信息和管理）
cache_manager = CacheManager()
data_processor = DataProcessor()
data_loader = DataLoader(cache_manager, data_processor)


@app.route('/')
def index():
    """渲染主页"""
    return render_template('index.html')


@app.route('/get_data')
def get_data_api():
    """
    提供数据API - 使用模块化数据加载系统
    """
    try:
        # 获取请求参数
        max_points = request.args.get('max_points', default=200, type=int)
        start_date = request.args.get('start_date', default=None, type=str)
        end_date = request.args.get('end_date', default=None, type=str)
        
        # 调用模块化API
        data = load_data(max_points, start_date, end_date)
        
        # 检查是否有错误
        if isinstance(data, tuple) and len(data) == 2 and isinstance(data[0], dict) and 'error' in data[0]:
            return jsonify(data[0]), data[1]
        
        return jsonify(data)
        
    except Exception as e:
        error_msg = f"API调用失败: {str(e)}"
        print(error_msg)
        return jsonify({'error': error_msg}), 500


@app.route('/get_date_range')
def get_date_range_api():
    """
    获取数据的日期范围API - 使用模块化数据加载系统
    """
    try:
        # 调用模块化API
        result = get_date_range()
        
        # 检查是否有错误
        if isinstance(result, tuple) and len(result) == 2 and isinstance(result[0], dict) and 'error' in result[0]:
            return jsonify(result[0]), result[1]
            
        return jsonify(result)
        
    except Exception as e:
        error_msg = f"获取日期范围失败: {str(e)}"
        print(error_msg)
        return jsonify({'error': error_msg}), 500


# 新增的管理API端点

@app.route('/api/data/info')
def get_data_info():
    """
    获取数据信息API
    """
    try:
        info = data_loader.get_data_info()
        return jsonify(info)
    except Exception as e:
        return jsonify({'error': f"获取数据信息失败: {str(e)}"}), 500


@app.route('/api/cache/clear', methods=['POST'])
def clear_cache_api():
    """
    清除缓存API
    """
    try:
        result = clear_cache()
        return jsonify(result)
    except Exception as e:
        return jsonify({'error': f"清除缓存失败: {str(e)}"}), 500


@app.route('/api/cache/info')
def get_cache_info_api():
    """
    获取缓存信息API
    """
    try:
        info = get_cache_info()
        return jsonify(info)
    except Exception as e:
        return jsonify({'error': f"获取缓存信息失败: {str(e)}"}), 500


@app.route('/api/data/reload', methods=['POST'])
def reload_data_api():
    """
    重新加载数据API
    """
    try:
        result = data_loader.reload_data()
        return jsonify(result)
    except Exception as e:
        return jsonify({'error': f"重新加载数据失败: {str(e)}"}), 500


@app.route('/api/data/source', methods=['GET', 'POST'])
def manage_data_source():
    """
    管理数据源API
    GET: 获取当前数据源信息
    POST: 更改数据源
    """
    try:
        if request.method == 'GET':
            # 返回当前数据源信息
            return jsonify({
                'current_data_path': data_loader.data_path,
                'file_exists': os.path.exists(data_loader.data_path),
                'cache_info': cache_manager.get_cache_info()
            })
            
        elif request.method == 'POST':
            # 更改数据源
            data = request.get_json()
            if not data or 'data_path' not in data:
                return jsonify({'error': '请提供data_path参数'}), 400
            
            new_data_path = data['data_path']
            result = data_loader.change_data_source(new_data_path)
            
            if result['status'] == 'error':
                return jsonify(result), 400
            else:
                return jsonify(result)
                
    except Exception as e:
        return jsonify({'error': f"管理数据源失败: {str(e)}"}), 500


@app.route('/api/data/validate', methods=['POST'])
def validate_data_file():
    """
    验证数据文件API
    """
    try:
        data = request.get_json()
        if not data or 'file_path' not in data:
            return jsonify({'error': '请提供file_path参数'}), 400
        
        file_path = data['file_path']
        is_valid, message = data_loader.validate_file_path(file_path)
        
        return jsonify({
            'is_valid': is_valid,
            'message': message,
            'file_path': file_path
        })
        
    except Exception as e:
        return jsonify({'error': f"验证文件失败: {str(e)}"}), 500


@app.route('/api/data/summary')
def get_data_summary():
    """
    获取数据摘要API
    """
    try:
        df = cache_manager.get_data_cache()
        if df is None:
            return jsonify({'error': '没有缓存数据，请先加载数据'}), 404
        
        summary = data_processor.get_data_summary(df)
        return jsonify(summary)
        
    except Exception as e:
        return jsonify({'error': f"获取数据摘要失败: {str(e)}"}), 500


@app.route('/api/system/status')
def get_system_status():
    """
    获取系统状态API
    """
    try:
        return jsonify({
            'timestamp': time.time(),
            'system_status': 'running',
            'cache_info': cache_manager.get_cache_info(),
            'data_path': data_loader.data_path,
            'file_exists': os.path.exists(data_loader.data_path),
            'module_versions': {
                'pandas': pd.__version__,
                'numpy': np.__version__
            }
        })
        
    except Exception as e:
        return jsonify({'error': f"获取系统状态失败: {str(e)}"}), 500


# 健康检查端点
@app.route('/health')
def health_check():
    """
    健康检查端点
    """
    try:
        # 检查数据文件是否存在
        file_exists = os.path.exists(data_loader.data_path)
        
        # 检查缓存状态
        cache_info = cache_manager.get_cache_info()
        
        status = 'healthy' if file_exists and cache_info['has_data_cache'] else 'degraded'
        
        return jsonify({
            'status': status,
            'timestamp': time.time(),
            'checks': {
                'data_file_exists': file_exists,
                'cache_available': cache_info['has_data_cache'],
                'cache_valid': cache_info['cache_valid']
            }
        })
        
    except Exception as e:
        return jsonify({
            'status': 'unhealthy',
            'error': str(e),
            'timestamp': time.time()
        }), 500


@app.route('/api/test-data')
def get_test_data():
    """
    获取测试数据API
    """
    try:
        test_data_path = 'data/test_data.csv'
        
        if not os.path.exists(test_data_path):
            return jsonify({
                'success': False,
                'error': '测试数据文件不存在'
            }), 404
        
        # 读取测试数据
        df = pd.read_csv(test_data_path)
        
        # 转换为字典列表
        data_list = df.to_dict('records')
        
        return jsonify({
            'success': True,
            'data': data_list,
            'count': len(data_list),
            'source': 'test_data.csv'
        })
        
    except Exception as e:
        return jsonify({
            'success': False,
            'error': f'读取测试数据失败: {str(e)}'
        }), 500





# 完整预测系统API
@app.route('/api/predict/complete', methods=['POST'])
def predict_complete():
    """调用完整预测系统"""
    try:
        data = request.get_json()
        input_file = data.get('input_file', 'data/realtime_sensor_data.csv')
        num_predictions = data.get('num_predictions', 96)
        models = data.get('models', ['rf', 'lstm', 'xgb'])
        
        # 确保输入文件存在
        if not os.path.exists(input_file):
            return jsonify({
                'success': False,
                'error': f'输入文件不存在: {input_file}'
            })
        
        # 调用完整预测系统
        script_path = os.path.join('predict', 'complete_room_prediction_system.py')
        if not os.path.exists(script_path):
            return jsonify({
                'success': False,
                'error': '预测系统脚本不存在'
            })
        
        # 构建命令参数
        cmd = [
            sys.executable, script_path,
            '--input', input_file,
            '--predictions', str(num_predictions),
            '--models'] + models + ['--api-mode']  # API模式，返回JSON
        
        print(f"执行预测命令: {' '.join(cmd)}")
        
        # 启动进程并实时读取输出
        process = subprocess.Popen(
            cmd,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            text=True,
            cwd=os.getcwd(),
            encoding='utf-8',
            errors='ignore'
        )
        
        # 存储所有输出
        all_output = []
        result_data = None
        
        # 实时读取输出
        while True:
            output = process.stdout.readline()
            if output == '' and process.poll() is not None:
                break
            
            if output:
                line = output.strip()
                all_output.append(line)
                
                # 解析进度信息
                if line.startswith('PROGRESS:'):
                    try:
                        progress_json = line[9:]  # 移除 "PROGRESS:" 前缀
                        progress_data = json.loads(progress_json)
                        
                        # 更新全局进度状态
                        prediction_progress.update({
                            'active': True,
                            'progress': progress_data.get('progress', 0),
                            'stage': progress_data.get('stage', ''),
                            'message': progress_data.get('message', ''),
                            'timestamp': progress_data.get('timestamp', '')
                        })
                        
                        print(f"Progress: {progress_data}")
                    except json.JSONDecodeError:
                        pass
                
                # 解析最终结果
                elif line.startswith('RESULT:'):
                    try:
                        result_json = line[7:]  # 移除 "RESULT:" 前缀
                        result_data = json.loads(result_json)
                        print(f"Result: {result_data}")
                    except json.JSONDecodeError:
                        pass
        
        # 等待进程完成
        process.wait()
        
        # 清除进度状态
        prediction_progress['active'] = False
        
        if process.returncode != 0:
            stderr = process.stderr.read()
            error_msg = stderr if stderr else '\n'.join(all_output)
            print(f"预测系统执行失败: {error_msg}")
            return jsonify({
                'success': False,
                'error': f'预测系统执行失败: {error_msg}'
            })
        
        # 返回结果
        if result_data and result_data.get('success'):
            return jsonify({
                'success': True,
                'result': result_data.get('data', {})
            })
        else:
            error_msg = result_data.get('error') if result_data else '未知错误'
            return jsonify({
                'success': False,
                'error': error_msg
            })
        
    except subprocess.TimeoutExpired:
        return jsonify({
            'success': False,
            'error': '预测系统执行超时'
        })
    except Exception as e:
        # 出错时清除进度状态
        prediction_progress['active'] = False
        print(f"完整预测API错误: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        })


# 获取预测进度API
@app.route('/api/predict/progress')
def get_prediction_progress():
    """获取当前预测进度"""
    return jsonify(prediction_progress)


@app.route('/api/prediction-results', methods=['POST'])
def get_prediction_results():
    """获取预测结果数据"""
    try:
        data = request.get_json()
        file_path = data.get('file_path')
        
        if not file_path or not os.path.exists(file_path):
            # 尝试查找最新的预测结果文件
            results_dir = 'data/predict_results'
            if os.path.exists(results_dir):
                files = [f for f in os.listdir(results_dir) if f.startswith('complete_room_prediction_') and f.endswith('.csv')]
                if files:
                    files.sort(reverse=True)  # 按时间倒序
                    file_path = os.path.join(results_dir, files[0])
                    print(f"使用最新预测结果文件: {file_path}")
                else:
                    return jsonify({
                        'success': False,
                        'error': '没有找到预测结果文件'
                    })
            else:
                return jsonify({
                    'success': False,
                    'error': '预测结果目录不存在'
                })
        
        # 读取预测结果CSV文件
        prediction_data = []
        with open(file_path, 'r', encoding='utf-8') as file:
            reader = csv.DictReader(file)
            for row in reader:
                prediction_data.append(row)
        
        return jsonify({
            'success': True,
            'data': prediction_data,
            'file_path': file_path,
            'record_count': len(prediction_data)
        })
        
    except Exception as e:
        print(f"获取预测结果错误: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        })


# ========== 模型预测API端点 ==========

def call_single_model_prediction(model_script, input_data):
    """
    调用单个模型预测脚本的通用函数
    
    Args:
        model_script (str): 模型脚本路径
        input_data (dict): 输入数据
    
    Returns:
        dict: 预测结果
    """
    try:
        # 构建输入数据字符串
        input_str = f"{input_data['date']},{input_data['time']}"
        for key in ['s1_temp', 's2_temp', 's3_temp', 's4_temp',
                   's1_light', 's2_light', 's3_light', 's4_light',
                   's1_sound', 's2_sound', 's3_sound', 's4_sound',
                   's5_co2', 's5_co2_slope', 's6_pir', 's7_pir']:
            input_str += f",{input_data[key]}"
        
        print(f"调用模型脚本: {model_script}")
        print(f"输入数据: {input_str}")
        
        # 调用模型脚本
        result = subprocess.run(
            [sys.executable, model_script],
            input=input_str,
            capture_output=True,
            timeout=30,
            text=True
        )
        
        if result.returncode == 0:
            # 解析输出
            try:
                output_text = result.stdout.decode('utf-8', errors='ignore') if isinstance(result.stdout, bytes) else result.stdout
            except:
                output_text = str(result.stdout)
            
            output_lines = output_text.strip().split('\n')
            print(f"模型输出: {output_lines}")
            
            # 查找预测结果
            prediction = None
            rounded_prediction = None
            
            for line in output_lines:
                line = line.strip()
                if '预测人数:' in line:
                    try:
                        # 提取预测人数后的数字
                        parts = line.split('预测人数:')
                        if len(parts) > 1:
                            number_str = parts[1].strip()
                            prediction = float(number_str)
                    except Exception as e:
                        print(f"解析预测人数失败: {e}, 行内容: {line}")
                        pass
                elif '四舍五入后的人数:' in line:
                    try:
                        # 提取四舍五入后的数字
                        parts = line.split('四舍五入后的人数:')
                        if len(parts) > 1:
                            number_str = parts[1].strip()
                            rounded_prediction = int(number_str)
                    except Exception as e:
                        print(f"解析四舍五入人数失败: {e}, 行内容: {line}")
                        pass
            
            if prediction is not None:
                # 确保有rounded_prediction
                if rounded_prediction is None:
                    rounded_prediction = round(prediction)
                return {
                    'success': True,
                    'prediction': prediction,
                    'rounded_prediction': rounded_prediction
                }
            else:
                return {
                    'success': False,
                    'error': '无法解析模型输出'
                }
        else:
            error_msg = result.stderr.strip() if result.stderr else result.stdout.strip()
            print(f"模型脚本执行失败: {error_msg}")
            return {
                'success': False,
                'error': f'模型执行失败: {error_msg}'
            }
        
    except subprocess.TimeoutExpired:
        return {
            'success': False,
            'error': '模型调用超时'
        }
    except Exception as e:
        print(f"调用模型时出错: {e}")
        return {
            'success': False,
            'error': f'调用模型时出错: {str(e)}'
        }


@app.route('/api/predict-rf', methods=['POST'])
def predict_rf():
    """随机森林模型预测API"""
    try:
        input_data = request.get_json()
        if not input_data:
            return jsonify({'success': False, 'error': '无效的输入数据'}), 400
        
        result = call_single_model_prediction('predict/predict_rf.py', input_data)
        
        if result['success']:
            return jsonify({
                'success': True,
                'data': {
                    'model': 'random_forest',
                    'prediction': result['prediction'],
                    'rounded_prediction': result['rounded_prediction']
                }
            })
        else:
            return jsonify(result), 500
        
    except Exception as e:
        print(f"随机森林预测API错误: {e}")
        return jsonify({'success': False, 'error': str(e)}), 500


@app.route('/api/predict-xgb', methods=['POST'])
def predict_xgb():
    """XGBoost模型预测API"""
    try:
        input_data = request.get_json()
        if not input_data:
            return jsonify({'success': False, 'error': '无效的输入数据'}), 400
        
        result = call_single_model_prediction('predict/predict_xgb.py', input_data)
        
        if result['success']:
            return jsonify({
                'success': True,
                'data': {
                    'model': 'xgboost',
                    'prediction': result['prediction'],
                    'rounded_prediction': result['rounded_prediction']
                }
            })
        else:
            return jsonify(result), 500
        
    except Exception as e:
        print(f"XGBoost预测API错误: {e}")
        return jsonify({'success': False, 'error': str(e)}), 500


@app.route('/api/predict-lstm', methods=['POST'])
def predict_lstm():
    """LSTM模型预测API"""
    try:
        input_data = request.get_json()
        if not input_data:
            return jsonify({'success': False, 'error': '无效的输入数据'}), 400
        
        result = call_single_model_prediction('predict/predict_lstm.py', input_data)
        
        if result['success']:
            return jsonify({
                'success': True,
                'data': {
                    'model': 'lstm',
                    'prediction': result['prediction'],
                    'rounded_prediction': result['rounded_prediction']
                }
            })
        else:
            return jsonify(result), 500
        
    except Exception as e:
        print(f"LSTM预测API错误: {e}")
        return jsonify({'success': False, 'error': str(e)}), 500


@app.route('/api/predict-ensemble', methods=['POST'])
def predict_ensemble():
    """集成模型预测API"""
    try:
        input_data = request.get_json()
        if not input_data:
            return jsonify({'success': False, 'error': '无效的输入数据'}), 400
        
        # 调用三个单模型
        rf_result = call_single_model_prediction('predict/predict_rf.py', input_data)
        xgb_result = call_single_model_prediction('predict/predict_xgb.py', input_data)
        lstm_result = call_single_model_prediction('predict/predict_lstm.py', input_data)
        
        # 收集成功的预测结果
        predictions = []
        result_data = {}
        
        if rf_result['success']:
            predictions.append(rf_result['rounded_prediction'])
            result_data['rf_prediction'] = rf_result['rounded_prediction']
        
        if xgb_result['success']:
            predictions.append(xgb_result['rounded_prediction'])
            result_data['xgb_prediction'] = xgb_result['rounded_prediction']
        
        if lstm_result['success']:
            predictions.append(lstm_result['rounded_prediction'])
            result_data['lstm_prediction'] = lstm_result['rounded_prediction']
        
        if not predictions:
            return jsonify({
                'success': False,
                'error': '所有模型预测都失败了'
            }), 500
        
        # 计算集成预测（简单平均）
        ensemble_prediction = round(sum(predictions) / len(predictions))
        result_data['ensemble_prediction'] = ensemble_prediction
        result_data['prediction'] = ensemble_prediction  # 兼容性
        
        return jsonify({
            'success': True,
            'data': result_data
        })
        
    except Exception as e:
        print(f"集成模型预测API错误: {e}")
        return jsonify({'success': False, 'error': str(e)}), 500


@app.route('/api/realtime-data', methods=['GET'])
def get_realtime_data():
    """
    获取实时传感器数据
    返回JSON格式的实时数据，包括传感器读数和预测的人数
    """
    try:
        # 读取实时数据JSON文件
        json_path = os.path.join('data', 'realtime_sensor_data.json')
        
        if not os.path.exists(json_path):
            return jsonify({
                'success': False,
                'error': '实时数据文件不存在'
            }), 404
        
        # 读取JSON数据
        with open(json_path, 'r', encoding='utf-8') as f:
            realtime_data = json.load(f)
        
        return jsonify({
            'success': True,
            'data': realtime_data
        })
        
    except json.JSONDecodeError as e:
        print(f"JSON解析错误: {e}")
        return jsonify({
            'success': False,
            'error': 'JSON数据格式错误'
        }), 500
    except Exception as e:
        print(f"获取实时数据错误: {e}")
        return jsonify({
            'success': False,
            'error': str(e)
        }), 500


if __name__ == '__main__':
    # 预加载数据到缓存
    print("=" * 50)
    print("启动房间占用监控系统")
    print("=" * 50)
    print("预加载数据到缓存...")
    
    preload_result = preload_data()
    
    if preload_result["status"] == "success":
        print("✓ 数据加载完成")
        print(f"✓ 记录数: {preload_result['summary']['total_records']}")
        print(f"✓ 日期范围: {preload_result['summary']['date_range']['start']} 到 {preload_result['summary']['date_range']['end']}")
    else:
        print("✗ 数据加载失败:")
        print(f"  错误: {preload_result['message']}")
    
    print("=" * 50)
    print("启动Flask服务器...")
    print("可用的API端点:")
    print("  - GET  /get_data          # 获取数据")
    print("  - GET  /get_date_range    # 获取日期范围")
    print("  - GET  /api/data/info     # 获取数据信息")
    print("  - POST /api/cache/clear   # 清除缓存")
    print("  - GET  /api/cache/info    # 获取缓存信息")
    print("  - POST /api/data/reload   # 重新加载数据")
    print("  - GET  /health            # 健康检查")
    print("=" * 50)
    
    app.run(debug=False, host='0.0.0.0', threaded=True)
